//
// Created by Cybaster on 2024/3/30.
//

#ifndef IMAGE_STITCHING_H
#define IMAGE_STITCHING_H

#include "helper.h"

#include <opencv2/opencv.hpp>

#include <string>

namespace stitch {


    enum GeometryType {
        GEOM_TYPE_POINT,
        GEOM_TYPE_LINE,
    };


    std::vector<cv::Vec3f>
    applyH_2D(const std::vector<cv::Vec3f> &geomObjects, const cv::Matx33f &H, GeometryType type);

    cv::Matx33f getCondition2D(const std::vector<cv::Vec3f> &points2D);

    cv::Mat_<float> getDesignMatrix_fundamental(const std::vector<cv::Vec3f> &p1_conditioned,
                                                const std::vector<cv::Vec3f> &p2_conditioned);

    cv::Matx33f solve_dlt_fundamental(const cv::Mat_<float> &A);

    cv::Matx33f forceSingularity(const cv::Matx33f &F);

    cv::Matx33f decondition_fundamental(const cv::Matx33f &T1, const cv::Matx33f &T2, const cv::Matx33f &F);

    cv::Matx33f getFundamentalMatrix(const std::vector<cv::Vec3f> &p1, const std::vector<cv::Vec3f> &p2);

    float getError(const cv::Vec3f &p1, const cv::Vec3f &p2, const cv::Matx33f &F);

    float getError(const std::vector<cv::Vec3f> &p1, const std::vector<cv::Vec3f> &p2, const cv::Matx33f &F);

    unsigned countInliers(const std::vector<cv::Vec3f> &p1, const std::vector<cv::Vec3f> &p2, const cv::Matx33f &F,
                          float threshold);

    cv::Matx33f estimateFundamentalRANSAC(const std::vector<cv::Vec3f> &p1, const std::vector<cv::Vec3f> &p2,
                                          unsigned numIterations, float threshold);

    void visualize(const cv::Mat &img1, const cv::Mat &img2, const std::vector<cv::Vec3f> &p1,
                   const std::vector<cv::Vec3f> &p2, const cv::Matx33f &F);

    void filterMatches(const RawOrbMatches &rawOrbMatches, std::vector<cv::Vec3f> &p1, std::vector<cv::Vec3f> &p2);

    void getPointsAutomatic(const cv::Mat &img1, const cv::Mat &img2, std::vector<cv::Vec3f> &p1,
                            std::vector<cv::Vec3f> &p2);

    void getRawPointsAutomatic(const cv::Mat &img1, const cv::Mat &img2, std::vector<cv::Vec3f> &p1,
                               std::vector<cv::Vec3f> &p2);

    cv::Mat_<float> getDesignMatrix_homography2D(const std::vector<cv::Vec3f> &conditioned_base,
                                                 const std::vector<cv::Vec3f> &conditioned_attach);

    cv::Matx33f solve_dlt_homography2D(const cv::Mat_<float> &A);

    cv::Matx33f decondition_homography2D(const cv::Matx33f &T_base, const cv::Matx33f &T_attach, const cv::Matx33f &H);

    cv::Matx33f homography2D(const std::vector<cv::Vec3f> &base, const std::vector<cv::Vec3f> &attach);

}

#endif // IMAGE_STITCHING_H